#pragma once
#include <iostream>
#include <set>
#include <errno.h>
#include <cstring>
#include <unistd.h>
#include <sys/epoll.h>
#include "Log.hpp"

namespace NS_Epoll
{
    using events_arr_ptr = struct epoll_event *;
    class Epoller
    {
        static const int maxevents = 32;
        static const int defaultepfd = -1;
        static const int size = 1024;

    public:
        Epoller() : _epfd(defaultepfd), _timeout(1000)
        {
        }

        void Create()
        {
            _epfd = epoll_create(size);
            if (_epfd == defaultepfd)
            {
                LOG(Abnormal, "failed to create epoll model, %d: %s\n", errno, strerror(errno));
                exit(1);
            }
            LOG(Info, "epoll model created successfully\n");
        }

        int Wait()
        {
            int n = epoll_wait(_epfd, _events, maxevents, _timeout);
            return n;
        }

        const events_arr_ptr GetEventsArr()
        {
            return _events;
        }

        bool Add(int fd, uint32_t event)
        {
            struct epoll_event ee;
            memset(&ee, 0, sizeof(ee));
            ee.events = event;
            ee.data.fd = fd;
            int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &ee);
            if (n == -1)
                return false;
            LOG(Info, "descriptor %d has been added to the epoll model\n", fd);
            fdlist.insert(fd);
            return true;
        }

        bool Mod(int fd, uint32_t event)
        {
            struct epoll_event ee;
            memset(&ee, 0, sizeof(ee));
            ee.events = event;
            ee.data.fd = fd;
            int n = epoll_ctl(_epfd, EPOLL_CTL_MOD, fd, &ee);
            if (n == -1)
                return false;
            LOG(Info, "descriptor %d has been modified to the epoll model\n", fd);
            return true;
        }

        bool Del(int fd)
        {
            int n = epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
            if (n == -1)
                return false;
            LOG(Info, "descriptor %d has been removed from the epoll model\n", fd);
            fdlist.erase(fd);
            return true;
        }

        ~Epoller()
        {
            if (_epfd != -1)
            {
                close(_epfd);
            }
            LOG(Info, "destroy the epoll model\n");
        }

        std::set<int> fdlist;
        void DebugPrint()
        {
            std::cout << "fd list: ";
            for (auto e : fdlist)
            {
                std::cout << e << " ";
            }
            std::cout << std::endl;
        }

    private:
        int _epfd;

        struct epoll_event _events[maxevents];
        int _timeout;
    };
}